using System.Collections.Generic;
using Engine;
using Engine.Graphics;
using Engine.OldSerialization;

namespace RuthlessConquest {
    public class GameImage {
        public class Serializer : ISerializer<GameImage> {
            public void Serialize(InputArchive archive, ref GameImage value) {
                value = new GameImage();
                archive.Serialize("StepIndex", ref value.StepIndex);
                archive.Serialize("PlanetImages", ref value.PlanetImages);
            }

            public void Serialize(OutputArchive archive, GameImage value) {
                archive.Serialize("StepIndex", value.StepIndex);
                archive.Serialize("PlanetImages", value.PlanetImages);
            }
        }

        public static PrimitivesRenderer2D PrimitivesRenderer2D = new();

        public static TexturedBatch2D CommonPlanetTexturedBatch2D {
            get {
                if (Textures.Planet == null) {
                    return null;
                }
                field ??= PrimitivesRenderer2D.TexturedBatch(Textures.Planet);
                return field;
            }
        }

        public static TexturedBatch2D SpecialPlanetTexturedBatch2D {
            get {
                if (Textures.Planet2 == null) {
                    return null;
                }
                field ??= PrimitivesRenderer2D.TexturedBatch(Textures.Planet2);
                return field;
            }
        }

        public static FlatBatch2D FlatBatch2D = PrimitivesRenderer2D.FlatBatch();

        public static int Scale = (int)MathUtils.Ceiling(MathUtils.Max(Game.WorldSize.X, Game.WorldSize.Y) / 127f);
        public int StepIndex;
        public DynamicArray<PlanetImage> PlanetImages = new();

        public static GameImage FromGame(Game game) {
            GameImage gameImage = new();
            gameImage.StepIndex = game.StepModule.StepIndex;
            foreach (Planet planet in game.PlanetsModule.Planets) {
                gameImage.PlanetImages.Add(
                    new PlanetImage {
                        Position = new Point2(planet.Position.X / Scale, planet.Position.Y / Scale),
                        SizeClass = planet.SizeClass,
                        Faction = planet.Faction
                    }
                );
            }
            return gameImage;
        }

        public void Draw(RenderTarget2D renderTarget, bool hidePlanetOwnership) {
            RenderTarget2D renderTarget2 = Display.RenderTarget;
            try {
                Display.RenderTarget = renderTarget;
                Display.Clear(Color.Transparent);
                foreach (PlanetImage planetImage in PlanetImages) {
                    float v = 1.7f * Planet.GetRadius(planetImage.SizeClass);
                    Color color = Planet.GetColor(planetImage.Faction);
                    if (hidePlanetOwnership && planetImage.Faction != Faction.Neutral) {
                        color = Color.White;
                    }
                    Point2 p = planetImage.Position * Scale;
                    CommonPlanetTexturedBatch2D.QueueQuad(
                        new Vector2(p) - new Vector2(v),
                        new Vector2(p) + new Vector2(v),
                        0f,
                        Vector2.Zero,
                        Vector2.One,
                        color
                    );
                }
                Vector2 vector = new Vector2(renderTarget.Width, renderTarget.Height) / new Vector2(Game.WorldSize);
                PrimitivesRenderer2D.Flush(Matrix.CreateScale(vector.X, vector.Y, 1f) * PrimitivesRenderer2D.ViewportMatrix());
            }
            finally {
                Display.RenderTarget = renderTarget2;
            }
        }

        public Texture2D Draw(Point2 size, bool hidePlanetOwnership) {
            RenderTarget2D renderTarget2D = new(size.X, size.Y, 1, ColorFormat.Rgba8888, DepthFormat.None);
            Draw(renderTarget2D, hidePlanetOwnership);
            return renderTarget2D;
        }

        public static Texture2D Draw(Point2 size, List<StructPlanet> planets, bool hidePlanetOwnership) {
            RenderTarget2D renderTarget = new(size.X, size.Y, 1, ColorFormat.Rgba8888, DepthFormat.None);
            RenderTarget2D originalRenderTarget = Display.RenderTarget;
            try {
                Display.RenderTarget = renderTarget;
                Display.Clear(Color.Transparent);
                foreach (StructPlanet planet in planets) {
                    float radius = 1.7f * Planet.GetRadius(planet.SizeClass);
                    Vector2 v = new(radius);
                    Color color = planet.IsSpecial ? Color.Gray : Planet.GetColor(planet.Faction);
                    if (hidePlanetOwnership && planet.Faction != Faction.Neutral) {
                        color = Color.White;
                    }
                    Vector2 position = new(planet.Position);
                    if (planet.IsSpecial) {
                        SpecialPlanetTexturedBatch2D.QueueQuad(position - v, position + v, 0f, Vector2.Zero, Vector2.One, color);
                    }
                    else {
                        CommonPlanetTexturedBatch2D.QueueQuad(position - v, position + v, 0f, Vector2.Zero, Vector2.One, color);
                    }
                    if (planet.SatellitesCount > 0) {
                        float temp = radius * 0.8f;
                        FlatBatch2D.QueueDisc(
                            new Vector2(position.X + temp, position.Y + temp),
                            new Vector2(95f),
                            Vector2.Zero,
                            0f,
                            color,
                            color,
                            5
                        );
                        if (planet.SatellitesCount > 1) {
                            FlatBatch2D.QueueDisc(
                                new Vector2(position.X - temp, position.Y - temp),
                                new Vector2(95f),
                                Vector2.Zero,
                                0f,
                                color,
                                color,
                                5
                            );
                        }
                    }
                }
                Vector2 vector = new Vector2(renderTarget.Width, renderTarget.Height) / new Vector2(Game.WorldSize);
                PrimitivesRenderer2D.Flush(Matrix.CreateScale(vector.X, vector.Y, 1f) * PrimitivesRenderer2D.ViewportMatrix());
            }
            finally {
                Display.RenderTarget = originalRenderTarget;
            }
            return renderTarget;
        }
    }
}